/**
 * This program starts simulation for the clock model
 */
package simulation;

import java.util.ArrayList;
import java.util.Date;

import org.apache.commons.math.stat.StatUtils;

/**
 * @author vladimir
 * 
 */
public class Main_clock {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// Parameters
		// Neighbors in spatial direction
		// int[][] neighbors = { { 0, 1 }, { 0, -1 }, { 1, 0 }, { -1, 0 },
		// { -1, -1 }, { 1, 1 } };
		// String modelName = "triang_clock";
		int[][] neighbors = { { 0, 1 }, { 0, -1 }, { 1, 0 }, { -1, 0 } };
		String modelName = "square_clock";



		// int[][] neighbors = { { 1 }, { -1 } };
		// String modelName = "chain_clock";

		// spatial coupling constant
		double J = 1;

		// Array describing size of the lattice
		int[] lRange = { 60, 90 };

		// Array describing temperature
		double[] tRange = {0.92, 1.00, 0.95, 0.96, 0.60, 0.62, 0.63, 0.64, 0.65, 0.70, 0.80, 0.90};
		// double[] tRange = common.Range.range(0.5, 1.2, 0.01);
		// double[] tRange = { 0.05 };

		// int[] qRange = common.Range.range(2, 11);
		int[] qRange = { 6, 6, 6, 6, 6};
		int dimension = neighbors[0].length;

		boolean info = true;

		for (int q : qRange) {
			for (int L : lRange) {
				for (double T : tRange) {
                    double tT = Math.round(1000 * T) / 1000.0d;
					java.util.Date Idate = new Date();

					CorrTime_clock Cor = new CorrTime_clock(neighbors, J, L, q, T);

					LatticeClock Lat = Cor.Lat;
					int MCS = -1;
					int Thermal_MCS = -1;
					if (Cor.ThermalMCS() > Cor.mcs) {
						// number of the Monte Carlo Sweeps
						MCS = Cor.MCS() - Cor.mcs;
						// number of the Monte Carlo Sweeps to reach equilibrium
						Thermal_MCS = Cor.ThermalMCS() - Cor.mcs;
					} else {
						// number of the Monte Carlo Sweeps
						MCS = Cor.MCS() - Cor.ThermalMCS();
						// number of the Monte Carlo Sweeps to reach equilibrium
						Thermal_MCS = 0;
					}

					// Correlation time
					int sweepStep = Cor.SweepStep();


					ArrayList<Double> tE = new ArrayList<Double>();
					ArrayList<Double> tM = new ArrayList<Double>();
					ArrayList<Double> tM2 = new ArrayList<Double>();
					ArrayList<Double> tM4 = new ArrayList<Double>();
					
					if (info) {
						System.out.println();
						System.out.println("modelName : " + modelName);
						System.out.println("J : " + J);
						System.out.println("q : " + q);
						System.out.println("L : " + L);
						System.out.println("T : " + tT);
						System.out.println("Monte Carlo Sweeps - " + Cor.MCS());

						System.out.println("Thermal Monte Carlo Sweeps - "
							+ Cor.ThermalMCS());
						System.out.println("Correlation time - " + sweepStep);
					}
					//path to save data
					String resultData = common.PathJoin.pathJoin("..","results", modelName, "J_"
						+ J, "q_" + q, "L_" + L);
					common.FSave.fSave(common.PathJoin.pathJoin(resultData,	"autoCorrelationTime"), 
						"T" + tT + "_" + Idate.getTime(), Cor.SweepStep());

					for (int sweep = 0; sweep < MCS; sweep++) {
						Lat.update();
						if ((sweep % sweepStep == 0) && (Thermal_MCS < sweep)){
							tE.add(Lat.Energy());
							double M = Lat.M();
							tM.add(M);
							tM2.add(Math.pow(M, 2));
							tM4.add(Math.pow(M, 4));

						}
					}

					// save data to file

					common.FSave.fSave(
						common.PathJoin.pathJoin(resultData, "Energy"), "T"
						+ tT + "_" + Idate.getTime(),
						StatUtils.mean(common.Todouble.todouble(tE)));

					common.FSave.fSave(
						common.PathJoin.pathJoin(resultData, "M"), "T" + tT
						+ "_" + Idate.getTime(),
						StatUtils.mean(common.Todouble.todouble(tM)));

					double X = Math.pow(L, dimension)
					* StatUtils.variance(common.Todouble.todouble(tM))
					/ T;

					common.FSave.fSave(
						common.PathJoin.pathJoin(resultData, "X"), "T" + tT
						+ "_" + Idate.getTime(), X);

					double M2 = StatUtils.mean(common.Todouble.todouble(tM2));

					common.FSave.fSave(
						common.PathJoin.pathJoin(resultData, "M2"), "T" + tT
						+ "_" + Idate.getTime(), M2);

					double M4 = StatUtils.mean(common.Todouble.todouble(tM4));
					common.FSave.fSave(
						common.PathJoin.pathJoin(resultData, "M4"), "T" + tT
						+ "_" + Idate.getTime(), M4);

					common.FSave.fSave(common.PathJoin.pathJoin(resultData, "cumulant"), "T" + tT
						+ "_" + Idate.getTime(), 1 - M4 / (3 * Math.pow(M2, 2)) );

                    double C = StatUtils.variance(common.Todouble.todouble(tE))
					/ Math.pow(T, dimension) * Math.pow(L, dimension);

					common.FSave.fSave(
						common.PathJoin.pathJoin(resultData, "C"), "T" + tT
						+ "_" + Idate.getTime(), C);

                    double V_L = Math.pow(L, dimension) * M2 / X;

                    common.FSave.fSave(common.PathJoin.pathJoin(resultData,
                            "V_L"),
                            "T" + tT + "_" + Idate.getTime(), V_L);

					if (info) {
						java.util.Date Fdate = new Date();
						long timeDiff = Fdate.getTime() - Idate.getTime();
						System.out.println("Waste of time: " + timeDiff);
					}
				}
			}
		}
	}
}